import { Header } from 'vitepress';
/**
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { DataGridColumn, ColumnGroupItem, DataGridProps } from '../data-grid.props';
import { Ref, ref } from 'vue';
import { DataGridHeaderCell, HeaderCellStatus } from './types';
import { ColumnRenderContext } from './use-column';

interface GroupColumnContext {
    groupedCells: Map<string, DataGridHeaderCell>;
    fieldToRootMap: Map<string, DataGridHeaderCell>;
}

export function useGroupColumn(props: DataGridProps, columnRenderContext: Ref<ColumnRenderContext>) {
    const columnGroups: Ref<ColumnGroupItem[] | undefined> = ref(props.columnOption?.groups);

    function buildGroupCell(
        columnGroupItem: ColumnGroupItem,
        originalHeaderCells: Map<string, DataGridHeaderCell>,
        parentCell: DataGridHeaderCell | null,
        rootCell: DataGridHeaderCell | null,
        context: GroupColumnContext
    ): DataGridHeaderCell {
        const groupCell: DataGridHeaderCell = {
            actualWidth: 0,
            children: [],
            depth: 1,
            field: columnGroupItem.field,
            layer: 1,
            left: 0,
            parent: parentCell,
            resizable: false,
            title: columnGroupItem.title || '',
            status: HeaderCellStatus.none,
            popoverRef: ref<any>(),
            showPopover: false,
            column: null,
            filterValue: null,
            sortType: 'none'
        };
        const actualRootCell = rootCell || groupCell;
        if (columnGroupItem.group) {
            let maxDepth = 1;
            columnGroupItem.group.reduce((parentGroupCell: DataGridHeaderCell, item: string | ColumnGroupItem) => {
                if (typeof item === 'string') {
                    const columnCell = originalHeaderCells.get(item);
                    if (columnCell) {
                        context.fieldToRootMap.set(item, actualRootCell);
                        parentGroupCell.actualWidth += columnCell.actualWidth;
                        parentGroupCell.children.push(columnCell);
                    }
                } else {
                    const subGroupCell = buildGroupCell(item, originalHeaderCells, parentGroupCell, actualRootCell, context);
                    maxDepth = Math.max(maxDepth, subGroupCell.depth);
                    parentGroupCell.actualWidth += subGroupCell.actualWidth;
                    parentGroupCell.children.push(subGroupCell);
                }
                return parentGroupCell;
            }, groupCell);
            groupCell.depth += maxDepth;
        }
        columnRenderContext.value.headerDepth = Math.max(columnRenderContext.value.headerDepth, groupCell.depth);
        return groupCell;
    }

    function buildGroupContext(originalHeaderCells: Map<string, DataGridHeaderCell>): GroupColumnContext {
        const context: GroupColumnContext = {
            groupedCells: new Map<string, DataGridHeaderCell>(),
            fieldToRootMap: new Map<string, DataGridHeaderCell>()
        };
        if (columnGroups.value) {
            columnGroups.value.reduce((groupContext: GroupColumnContext, item: ColumnGroupItem) => {
                const groupCell = buildGroupCell(item, originalHeaderCells, null, null, context);
                groupContext.groupedCells.set(item.field, groupCell);
                return groupContext;
            }, context);
        }
        return context;
    }

    function getGroupedCellLeft(mergedCell: DataGridHeaderCell[]) {
        if (!mergedCell || mergedCell.length === 0) {
            return 0;
        }
        const firstCell = mergedCell[0];
        const isFirstCellHasChildren = firstCell.children && firstCell.children.length > 0;
        if (isFirstCellHasChildren) {
            firstCell.left = getGroupedCellLeft(firstCell.children);
        }
        return firstCell.left;
    }

    function resetGroupedCellsLayer(mergedCell: DataGridHeaderCell[], parent?: DataGridHeaderCell) {
        const maxGroupDepth = columnRenderContext.value.headerDepth;
        mergedCell.forEach((headerCell: DataGridHeaderCell) => {
            headerCell.layer = parent ? parent.layer + 1 : 1;
            const isDetail = headerCell.children && headerCell.children.length === 0;
            headerCell.depth = isDetail ? maxGroupDepth - (headerCell.layer - 1) : 1;
            headerCell.left = isDetail ? headerCell.left : getGroupedCellLeft(headerCell.children);
            if (headerCell.children) {
                resetGroupedCellsLayer(headerCell.children, headerCell);
            }
        });
    }

    function mergeGroupedCells(
        originalHeaderCells: Map<string, DataGridHeaderCell>,
        groupContext: GroupColumnContext
    ): Map<string, DataGridHeaderCell> {
        const mergedCells = new Map<string, DataGridHeaderCell>();
        originalHeaderCells.forEach((gridHeaderCell: DataGridHeaderCell) => {
            const rootGroupCellToField = groupContext.fieldToRootMap.get(gridHeaderCell.field);
            const hasBeenGrouped = rootGroupCellToField != null;
            if (hasBeenGrouped && !mergedCells.has(rootGroupCellToField.field)) {
                mergedCells.set(rootGroupCellToField.field, rootGroupCellToField);
            }
            if (!hasBeenGrouped) {
                mergedCells.set(gridHeaderCell.field, gridHeaderCell);
            }
        });
        resetGroupedCellsLayer(Array.from(mergedCells.values()));
        return mergedCells;
    }

    function getGridHeaderCells(columns: DataGridColumn[]): Map<string, DataGridHeaderCell> {
        let headerCells = new Map<string, DataGridHeaderCell>();

        let cellPosition = 0;
        columns.reduce((previousHeaderCells: Map<string, DataGridHeaderCell>, dataGridColumn: DataGridColumn) => {
            let headerStatus = HeaderCellStatus.none;
            headerStatus = dataGridColumn.sortable ? headerStatus | HeaderCellStatus.sortable : headerStatus;
            headerStatus = dataGridColumn.filterable ? headerStatus | HeaderCellStatus.filterable : headerStatus;
            headerStatus = dataGridColumn.sort && dataGridColumn.sort !== 'none' ?
                headerStatus | HeaderCellStatus.sorted | (
                    dataGridColumn.sort === 'asc' ? HeaderCellStatus.ascending : HeaderCellStatus.descending
                )
                : headerStatus;
            previousHeaderCells.set(dataGridColumn.field, {
                actualWidth: dataGridColumn.actualWidth || 0,
                children: [],
                depth: 1,
                layer: 1,
                left: cellPosition,
                field: dataGridColumn.field,
                parent: null,
                resizable: dataGridColumn.resizable || false,
                title: dataGridColumn.title,
                status: headerStatus,
                popoverRef: ref<any>(),
                showPopover: false,
                column: dataGridColumn,
                filterValue: null,
                sortType: dataGridColumn.sort || 'none',
                showSetting: dataGridColumn.showSetting
            } as DataGridHeaderCell);
            cellPosition += dataGridColumn.actualWidth || 0;
            return previousHeaderCells;
        }, headerCells);

        if (columnGroups.value) {
            const groupContext = buildGroupContext(headerCells);
            headerCells = mergeGroupedCells(headerCells, groupContext);
        }

        return headerCells;
    }

    return { getGridHeaderCells };
}
